package com.apes.scm.voucher.service.builder;

import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.service.InvoiceService;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.ValuationService;
import com.apes.scm.voucher.service.VoucherService;
import com.apes.scm.voucher.service.VoucherType;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManager;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 功能：采购订单凭证构造器
 *
 * @author xul
 * @create 2018-10-18 9:26
 */
@Component
public class PurchaseOrderVoucherBuilder extends AbstractVoucherBuilder {

    @Autowired
    private ValuationService valuationService;

    @Autowired
    private InventoryService inventoryService;

    public PurchaseOrderVoucherBuilder() {
        this.voucherType = VoucherType.SUPPLIER_PURCHASE;
        this.BusinessTypes = new String[]{BusinessType.PURCHASE_ORDER};
    }

    /**
     * 功能：创建凭证
     *
     * @param voucher
     */
    @Override
    public Voucher create(Voucher voucher) {
        voucher.setReturned(false);

        if (!("Supplier".equals(voucher.getPartner().getRole().getId()))) {
            throw new RuntimeException("采购凭证请指定供应角色的合作伙伴[" + voucher.getPartner().getId() + "]!");
        }

        /**保存凭证**/
        voucher = save(voucher);

        /**成本核算/价值评估**/
        costing(voucher);

        /**跨公司/公司间交易**/
        crossCompanyTransaction(voucher);

        /**暂估款**/
        changCurrentProvisional(voucher, 1);

        /**账单：用于跨公司内部交易记帐**/
        if (voucher.isInvoiced() && voucher.getInventoryMode().equals(InventoryMode.IM_OWN)) {
            invoiced(voucher);
        }

        return voucher;
    }

    /**
     * 功能：凭证冲销
     */
    @Override
    public Voucher writeOff(Voucher voucher) {
        /**第一步：检查价值库存是否被消耗或冻结**/
        voucher.getVoucherItems().forEach(item -> {
            List<VoucherInventory> inventories = valuationService.findByVoucherItem(item);
            inventories.stream().forEach(inventory -> {
                InventoryBatch inventoryBatch = inventory.getInventoryBatch();
                if (inventoryBatch.getFrostQty() != 0) {
                    throw new RuntimeException("价值库存被冻结，不允许冲销！");
                }
                if (inventoryBatch.getBalanceQty() != inventoryBatch.getPurchaseQty()) {
                    throw new RuntimeException("价值库存被消耗，不允许冲销！");
                }
            });
        });

        /**第二步：冲销凭证**/
        Voucher purchaseReturnVoucher = createPurchaseReturnVoucher(voucher);

        /**第三步：帐单**/
        Invoice invoice = SpringManager.getBean(InvoiceService.class).findBySourceBusinessTypeAndSource(voucher.getInnerBusinessType(), voucher.getId());
        if (invoice != null) {
            invoiced(purchaseReturnVoucher);
        }

        return purchaseReturnVoucher;
    }

    /**
     * 内部采购退货
     *
     * @param voucher 凭证
     * @return Voucher 采购退货凭证
     */
    private Voucher createPurchaseReturnVoucher(Voucher voucher) {
        Voucher purchaseReturnVoucher = new Voucher();
        purchaseReturnVoucher.setBusinessType(BusinessType.PURCHASE_RETURN);
        String[] fields = {"company", "partner", "contract", "dept", "clerk", "inventoryMode", "accountingMethod", "originBusinessType", "origin"};
        ReflectUtil.copy(voucher, purchaseReturnVoucher, fields);
        purchaseReturnVoucher.setSourceBusinessType(voucher.getInnerBusinessType());
        purchaseReturnVoucher.setSource(voucher.getId());
        purchaseReturnVoucher.setReturned(true);

        Set<VoucherItem> returnItems = new HashSet<>();
        voucher.getVoucherItems().stream().forEach((vItem) -> {

            /** 第一步：找采购退货批次 **/
            new BatchMethod<Batch>() {

                /**
                 * 功能：数据包装
                 * @return
                 */
                @Override
                public Iterable<Batch> wrap() {
                    List<InventoryBatch> inventories = valuationService.findByVoucherItem(vItem).stream()
                            .map(voucherInventory -> voucherInventory.getInventoryBatch()).collect(Collectors.toList());
                    return inventoryService.wrapBatch(inventories, vItem.getUom(), inventory -> inventory.getBalanceQty());
                }

                /**
                 * 功能：批次处理
                 *
                 * @param batch
                 * @param increment
                 */
                @Override
                public void succeed(Batch batch, double increment) {
                    InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                    inventoryService.changeFrostQty(inventoryBatch, vItem.getUom(), increment, voucher.getCompany(), voucher.getInnerBusinessType(), voucher.getId(), String.valueOf(vItem.getId()), "内部采购退货批次处理");
                    VoucherItem voucherItem = new VoucherItem();
                    voucherItem.setProduct(vItem.getProduct());
                    voucherItem.setUom(vItem.getUom());
                    voucherItem.setOriginItemId(vItem.getOriginItemId());
                    voucherItem.setSourceItemId(String.valueOf(vItem.getId()));
                    voucherItem.setInventoryBatch(inventoryBatch);
                    voucherItem.setPriceUnit(vItem.getPriceUnit());
                    voucherItem.setProductQty(-1 * increment);
                    voucherItem.setTax(vItem.getTax());
                    voucherItem.setVoucher(purchaseReturnVoucher);
                    returnItems.add(voucherItem);
                }

                /**
                 * 功能：数量不足后异常处理
                 *
                 * @param surplus
                 */
                @Override
                public void error(double surplus) {
                    throw new RuntimeException("商品：["+vItem.getProduct().getId()+"]" + vItem.getProduct().getName() + " 价值库存数量少 " + surplus + vItem.getProduct().getUom().getName() + "！");
                }
            }.execute(Math.abs(vItem.getProductQty()));
        });

        purchaseReturnVoucher.setVoucherItems(returnItems);
        return SpringManager.getBean(VoucherService.class).save(purchaseReturnVoucher);
    }
}
